package ginx

import (
	"net/http"

	"gitee.com/youkelike/zlog"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

func Wrap(l zlog.Logger, fn func(ctx *gin.Context) (Result, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		res, err := fn(ctx)
		if err != nil {
			// 开始处理 error，其实就是记录一下日志
			l.Errorw("处理业务逻辑出错",
				"path", ctx.Request.URL.Path,
				// 命中的路由
				"route", ctx.FullPath(),
				"err", err)
			if ctx.Writer.Status() == http.StatusOK {
				ctx.Status(http.StatusInternalServerError)
			}
		}
		ctx.JSON(ctx.Writer.Status(), res)
	}
}

func WrapToken[C jwt.Claims](l zlog.Logger, fn func(ctx *gin.Context, uc C) (Result, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		val, ok := ctx.Get("users")
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		c, ok := val.(C)
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		res, err := fn(ctx, c)
		if err != nil {
			l.Errorw("处理业务逻辑出错",
				zlog.String("path", ctx.Request.URL.Path),
				// 命中的路由
				zlog.String("route", ctx.FullPath()),
				zlog.Err(err))
			ctx.Status(500)
		}
		// 直接能拿到响应码
		ctx.JSON(ctx.Writer.Status(), res)
	}
}

func WrapBodyAndToken[Req any, C jwt.Claims](l zlog.Logger, fn func(ctx *gin.Context, req Req, uc C) (Result, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var req Req
		if err := ctx.Bind(&req); err != nil {
			l.Debugw("解析请求参数失败", "err", err)
			ctx.JSON(http.StatusBadRequest, Result{Code: http.StatusBadRequest, Msg: "请求参数解析失败"})
			return
		}

		val, ok := ctx.Get("users")
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		c, ok := val.(C)
		if !ok {
			ctx.AbortWithStatus(http.StatusUnauthorized)
			return
		}

		res, err := fn(ctx, req, c)
		if err != nil {
			l.Errorw("处理业务逻辑出错",
				zlog.String("path", ctx.Request.URL.Path),
				// 命中的路由
				zlog.String("route", ctx.FullPath()),
				zlog.Err(err))
			if ctx.Writer.Status() == http.StatusOK {
				ctx.Status(http.StatusInternalServerError)
			}
		}
		// 直接能拿到响应码
		ctx.JSON(ctx.Writer.Status(), res)
	}
}

// T 就是 dto
func WrapBody[T any](l zlog.Logger, fn func(ctx *gin.Context, req T) (Result, error)) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		var req T
		if err := ctx.Bind(&req); err != nil {
			l.Debugw("解析请求参数失败", "err", err)
			ctx.JSON(http.StatusBadRequest, Result{Code: http.StatusBadRequest, Msg: "请求参数解析失败"})
			return
		}

		res, err := fn(ctx, req)
		if err != nil {
			l.Errorw("处理业务逻辑出错",
				zlog.String("path", ctx.Request.URL.Path),
				// 命中的路由
				zlog.String("route", ctx.FullPath()),
				zlog.Err(err))
			if ctx.Writer.Status() == http.StatusOK {
				ctx.Status(http.StatusInternalServerError)
			}
		}
		// 直接能拿到响应码
		ctx.JSON(ctx.Writer.Status(), res)
	}
}
